# -*- coding: utf-8 -*-
import datetime
import json
import random
import neomodel
from neomodel import db
from plg import settings
import paho.mqtt.client as mqtt
import pandas as pd
import time
from neomodel import config

config.DATABASE_URL = 'bolt://neo4j:123@localhost:17687'

from network.models import Person


def viliad_rel(card_id1: str, card_id2: str, location_id: str, degree_of_contact: float, contact_timestamp):
    """
    1. 今天之内都没有的时候存
    2. 今天之内有了,并且接触深度比当前小的存
    :param uid1:
    :param uid2:
    :param location_id: 接触位置
    :param degree_of_contact:  接触距离
    :param contact_timestamp: 当前接触的时间戳
    :return:
    """
    # 1. 查出
    cypher = f"""
        MATCH (:Person{{ card_id:"{card_id1}"}})-[r:CONTACT ]-(:Person {{card_id:"{card_id2}"}}) return r.shaftWidth, r.time
    """
    print(cypher)
    try:
        db_degree, db_timestamp = db.cypher_query(cypher)[0][0]
    except:
        return '创建'
    # 拿到最近一次接触的时间，看是不是同一天
    # 小于一天,
    if contact_timestamp - db_timestamp < 86400:
        if db_degree < degree_of_contact:
            """这个应该是更新, 不是创建"""
            """更新"""
            return "更新"  # 接触在同一天,且接触强度更深
        else:
            return False
    return "创建"  # 所有的接触都不在同一天
    # 判断接触程度是否变深


def update_rel(card_id1: str, card_id2: str, location_id: str, degree_of_contact: float):
    """
    :param id1: 用户1的id str : 1
    :param id2: 用户2的id str: 2
    :param location_id: 阅读器id str: 1
    :param time: 接触时间: float
    :param degree_of_contact: 接触程度
    :return:
    """
    # 校验参
    if degree_of_contact > 10 or degree_of_contact < 0:
        print(f"degree_of_contact为{degree_of_contact}, 请输入0~10的范围")
    try:
        s_person = Person.nodes.get(card_id=card_id1)  # 每次fiter都会对person_ser进行筛选， 返回筛选的值
    except Person.DoesNotExist:
        not_found_msg = f'没找到卡号为{card_id1}的用户'
        print(not_found_msg)
        return None
    try:
        o_person = Person.nodes.get(card_id=card_id2)
    except Person.DoesNotExist:
        not_found_msg = f'没找到卡号为{card_id2}的用户'
        print(not_found_msg)
        return None
    rels = s_person.contact.relationship(o_person)
    if not rels:
        print('这两个用户之间没有关系')
        return None

    rels.update(location_id, degree_of_contact)
    return {
        "code": "200",
        'data': rels.serialize
    }


def creat_rel(card_id1: str, card_id2: str, location_id: str, degree_of_contact: float):
    """
    :param id1: 用户1的id str : 1
    :param id2: 用户2的id str: 2
    :param location_id: 阅读器id str: 1
    :param time: 接触时间: float
    :param degree_of_contact: 接触程度
    :return:
    """
    # 校验参

    if degree_of_contact > 10 or degree_of_contact < 0:
        print(f"degree_of_contact为{degree_of_contact}, 请输入0~10的范围")
    try:
        p1 = Person.nodes.get(card_id=card_id1)
        p2 = Person.nodes.get(card_id=card_id2)
        res = p1.contact.connect(p2, {'location_id': location_id, 'shaftWidth': degree_of_contact})
        print(res.serialize)

    except neomodel.DoesNotExist:
        print("未查询到用户")


def delete_rel(card_id1: str, card_id2: str):
    """
    删除两个用户的所有关系
    :param uid1:
    :param uid2:
    :return:
    """
    cypher = f"""
        match ({{card_id:{card_id1}}})-[r]-({{card_id:{card_id2}}}) delete r
    """
    print(cypher)
    rel = db.cypher_query(cypher)


class MQTTClinet():
    def __init__(self):
        self.message = []
        pass

    # 一旦有log，回调此方法
    def on_log(self, mqttc, obj, level, string):
        # print('*'*10)
        # print("有日志了")
        # print('on_log')
        # print('mqttc: ', mqttc) # mqttc:  <paho.mqtt.client.Client object at 0x7fcda1b68e10>
        # print('obj: ', obj) # obj:  None
        # print('level: ', level) # level:  16
        print('string: ', string)  # string:  Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'2019135229'
        # print('*'*10)

    def on_connect(self, mqttc, obj, flags, rc):
        print('*' * 10)
        print('on_connect')
        print('mqttc: ', mqttc)  # mqttc:  <paho.mqtt.client.Client object at 0x7fcda1b68e10>
        print('obj: ', obj)  # obj:  None
        print('flags: ', flags)  # flags:  {'session present': 0}
        print('rc: ', rc)  # rc:  0
        print('*' * 10)

    # 一旦订阅到消息，回调此方法
    def on_message(self, mqttc, obj, msg):
        """

        :param mqttc:
        :param obj:
        :param msg:  解压之后       # 黄旭的
                                    {'location_id': '3400',
                                    'users': [
                                        {'user_id': 'c224be0020003fb0bd240004', 'signal_distance': 3.5},
                                        {'user_id': 'e28068940000400bb9834c26', 'signal_distance': 2.5},
                                        {'user_id': 'e28068940000400bb9834c26', 'signal_distance': 2.5}
                                        ]
                                    }

                              # 1. 两个相同id,
                                     # 春风的
                                    {
                                        "location_id" : "1", // 阅读器id
                                        "users" : [
                                            {
                                                "s_user_id" : "03", // 接触id2
                                                "o_user_id" : "02", // 接触id2
                                                "relative_distance": "00" // 相对距离3米
                                            },
                                            {
                                                "s_user_id" : "01", // 接触id2
                                                "o_user_id" : "02", // 接触id2
                                                "relative_distance": "01" // 相对距离3米
                                            }，
                                            {
                                                "s_user_id" : "04", // 接触id2
                                                "o_user_id" : "02", // 接触id2
                                                "relative_distance": "01" // 相对距离3米
                                            }，
                                            {
                                                "s_user_id" : "02", // 接触id2
                                                "o_user_id" : "03", // 接触id2
                                                "relative_distance": "01" // 相对距离3米
                                            }，
                                            {
                                                "s_user_id" : "04", // 接触id2
                                                "o_user_id" : "03", // 接触id2
                                                "relative_distance": "01" // 相对距离3米
                                            }，
                                            {
                                                "s_user_id" : "01", // 接触id2
                                                "o_user_id" : "03", // 接触id2
                                                "relative_distance": "01" // 相对距离3米
                                            }，
                                        ]
                                    }

        :return:
        """
        """
        {'location_id': '3400', 'users': [{'user_id': 'c224be0020003fb0bd240004', 'signal_distance': 3.5},
                              {'user_id': 'e28068940000400bb9834c26', 'signal_distance': 2.5},
                              {'user_id': 'e28068940000400bb9834c26', 'signal_distance': 2.5}]}
                              # 1. 两个相同id, 取平均
        """

        # 1. 解析数据
        data_dict = eval(msg.payload.decode('utf-8'))
        print("data_dict",data_dict)
        # 2. 黄旭的数据要转换
        if data_dict.get('users'):
            location_id = data_dict.get('location_id')
            users = data_dict.get('users')
            contact_timestamp = time.time()
            if not all((location_id, users)):
                print('参数不全')
                return False
            if users[0].get('signal_distance'):  # 黄旭给的数据
                users_df = pd.DataFrame(data_dict.get('users'))
                users_df = users_df.groupby('user_id').mean()  # 当id重复的时候， 求平均值
                # 循环全部人
                for i in range(users_df.shape[0] - 1):
                    s_user = users_df.iloc[i]
                    for j in range(i + 1, users_df.shape[0]):
                        o_user = users_df.iloc[j]
                        degree = abs(s_user.get('signal_distance') - o_user.get('signal_distance')) / 10
                        # 判断

                        # delete_rel(s_user.name, o_user.name)
                        action = viliad_rel(s_user.name, o_user.name, location_id, degree, contact_timestamp)
                        if action:
                            if action == "更新":
                                update_rel(s_user.name, o_user.name, location_id, degree)
                            else:
                                creat_rel(s_user.name, o_user.name, location_id, degree)

            else:  # 春风给的数据
                # 1. 都拿去创建
                for i in users:
                    try:
                        s_user_id = str(int(i.get('s_user_id')))  # 去除前面的零
                        o_user_id = str(int(i.get('o_user_id')))
                        degree = int(i.get('relative_distance'), 16)
                        # 双向认证
                        action = viliad_rel(s_user_id, o_user_id, location_id, degree, contact_timestamp=contact_timestamp)
                        if action:
                            if action == "更新":
                                update_rel(s_user_id, o_user_id, location_id, degree)
                            else:
                                creat_rel(s_user_id, o_user_id, location_id, degree)
                    except:
                        continue
                # 2. 判断这个关系是否要创建

                # 3. 创建关系
                pass


    # 一旦订阅成功，回调此方法
    def on_subscribe(self, mqttc, obj, mid, granted_qos):
        pass
        # print('*'*10)
        # print("订阅成功了")
        # print('on_subscribe')
        # print('mqttc: ', mqttc)  # mqttc:  <paho.mqtt.client.Client object at 0x7fcda1b68e10>
        # print('obj: ', obj) # obj:  None
        # print('mid: ', mid) # mid:  1
        # print('granted_qos: ', granted_qos) # granted_qos:  (0,)
        print('订阅成功了')
        print("Subscribed: " + str(mid) + " " + str(granted_qos))  # Subscribed: 1 (0,)
        # print('*'*10)

    def run_server(self):
        # 新建mqtt客户端，默认没有clientid，clean_session=True, transport="tcp"
        mqttc = mqtt.Client(client_id="123210")
        mqttc.on_message = self.on_message  # 一旦订阅到消息，回调此方法
        mqttc.on_connect = self.on_connect  # 一旦连接成功，回调此方法
        mqttc.on_subscribe = self.on_subscribe  # 一旦订阅成功，回调此方法
        mqttc.on_log = self.on_log  # # 一旦有log，回调此方法
        # 连接broker，心跳时间为60s
        mqttc.connect("47.108.197.242")  # 用的tcp协议
        # 订阅该主题，QoS=0
        mqttc.subscribe("testtopic/")
        mqttc.loop_forever()


# 1883	MQTT/TCP 协议端口
# 18083 http服务通过网页管理
# 8083 MQTT/WS 协议端口


if __name__ == '__main__':
    mqtt_client = MQTTClinet()

    # mqtt_client.on_message(None, None, None)
    mqtt_client.run_server()
    # print(message)
    # DEBUG:root:debug message
    #
